package today.wxp.blog.spark.structed.streaming.util

import java.text.{ParseException, SimpleDateFormat}
import java.util.Date

import net.liftweb.json.{CustomSerializer, DateFormat, Serializer, _}

/**
  * 序列化/反序列化
  * <p/>
  * Author   : wangxp
  * <p/>
  * DateTime : 2017/5/29 20:59
  */
class DeSerialization(datePattern: String)
{
  /**
    * 自定义的SQL DATE序列化函数。
    *
    * @param formats 格式化参数。
    *
    * @return (反序列化函数, 序列化函数)
    */
  def customSqlDateSer(formats: Formats): (PartialFunction[JValue, java.sql.Date], PartialFunction[Any, JValue]) =
  {
    val deserializeFunc: PartialFunction[JValue, java.sql.Date] = (json: JValue) => json match
    {
      case v: JString => formats.dateFormat.parse(v.s).map(d => new java.sql.Date(d.getTime)).orElse(null).get
    }

    val serializeFunc: PartialFunction[Any, JValue] = (d: Any) => d match
    {
      case d: java.sql.Date => JString(formats.dateFormat.format(d))
    }

    (deserializeFunc, serializeFunc)
  }

  implicit val formats = new Formats
  {
    override val dateFormat = new DateFormat
    {

      override def parse(s: String): Option[Date] = try
      {
        Some(formatter.parse(s))
      }
      catch
      {
        case _: ParseException => None
      }

      override def format(d: java.util.Date): String = formatter.format(d)

      private def formatter =
      {
        new SimpleDateFormat(datePattern)
      }
    }

    override val customSerializers: List[Serializer[_]] = List(new CustomSerializer[java.sql.Date](customSqlDateSer))
  }

  /**
    * 将JSON数据反序列化为指定对象。
    *
    * @param json 需要反序列化的JSON字符串。
    * @tparam A 反序列化目标类。
    *
    * @return 反序列化目标对象。
    */
  def deserialize[A](json: String)(implicit mf: scala.reflect.Manifest[A]): A =
  {
    //解析对象
    parse(json).extract[A]
  }

  /**
    * 序列化对象为JSON字符串。
    *
    * @param obj 需要序列化的对象。
    *
    * @return 序列化对象后生成的JSON字符串。
    */
  def serialize(obj: AnyRef): String =
  {
    import net.liftweb.json.Serialization.write
    write(obj)
  }

  /**
    * 移除JSON中指定字段。
    *
    * @param json      目标JSON字符串。
    * @param fieldName 需要移除字段的名称。
    *
    * @return 移除指定字段后的JSON字符串。
    */
  def removeField(json: String, fieldName: String): String =
  {
    val jObj = parse(json)
    val collectionNameField = jObj \ fieldName

    serialize(jObj.remove(_ == collectionNameField))
  }

  /**
    * 抽取指定字段名称的值。
    *
    * @param json      目标JSON字符串。
    * @param fieldName 需要抽取的字段名称。
    * @tparam A 抽取字段的类型。
    *
    * @return 抽取字段的值。
    */
  def extractFieldValue[A](json: String, fieldName: String)(implicit mf: scala.reflect.Manifest[A]): A =
  {
    (parse(json) \ fieldName).extract[A]
  }
}
